home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
AmigActive 2
/
AACD 2.iso
/
AACD
/
Magazine
/
GraphicsCards
/
StormMesa
/
src
/
matrix.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-02-04
|
28KB
|
982 lines
/* $Id: matrix.c,v 3.7 1998/08/23 22:18:18 brianp Exp $ */
/*
* Mesa 3-D graphics library
* Version: 3.0
* Copyright (C) 1995-1998 Brian Paul
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* $Log: matrix.c,v $
* Revision 3.7 1998/08/23 22:18:18 brianp
* added Driver.Viewport and Driver.DepthRange function pointers
*
* Revision 3.6 1998/06/07 22:18:52 brianp
* implemented GL_EXT_multitexture extension
*
* Revision 3.5 1998/05/07 00:12:57 brianp
* new invert_matrix() function from Jacques Leroy
*
* Revision 3.4 1998/03/27 04:17:31 brianp
* fixed G++ warnings
*
* Revision 3.3 1998/03/03 02:39:29 brianp
* fixed divide by zero problem in gl_LoadMatrixf() (Tim Rowley)
*
* Revision 3.2 1998/02/20 04:50:44 brianp
* implemented GL_SGIS_multitexture
*
* Revision 3.1 1998/02/08 20:19:12 brianp
* removed unneeded headers
*
* Revision 3.0 1998/01/31 20:58:46 brianp
* initial rev
*
*/
/*
* Matrix operations
*
*
* NOTES:
* 1. 4x4 transformation matrices are stored in memory in column major order.
* 2. Points/vertices are to be thought of as column vectors.
* 3. Transformation of a point p by a matrix M is: p' = M * p
*
*/
#ifdef PC_HEADER
#include "all.h"
#else
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "context.h"
#include "macros.h"
#include "matrix.h"
#include "mmath.h"
#include "types.h"
#endif
static GLfloat Identity[16] = {
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0
};
#if 0
static void print_matrix( const GLfloat m[16] )
{
int i;
for (i=0;i<4;i++) {
printf("%f %f %f %f\n", m[i], m[4+i], m[8+i], m[12+i] );
}
}
#endif
/*
* Perform a 4x4 matrix multiplication (product = a x b).
* Input: a, b - matrices to multiply
* Output: product - product of a and b
* WARNING: (product != b) assumed
* NOTE: (product == a) allowed
*/
static void matmul( GLfloat *product, const GLfloat *a, const GLfloat *b )
{
/* This matmul was contributed by Thomas Malik */
GLint i;
#define A(row,col) a[(col<<2)+row]
#define B(row,col) b[(col<<2)+row]
#define P(row,col) product[(col<<2)+row]
/* i-te Zeile */
for (i = 0; i < 4; i++) {
GLfloat ai0=A(i,0), ai1=A(i,1), ai2=A(i,2), ai3=A(i,3);
P(i,0) = ai0 * B(0,0) + ai1 * B(1,0) + ai2 * B(2,0) + ai3 * B(3,0);
P(i,1) = ai0 * B(0,1) + ai1 * B(1,1) + ai2 * B(2,1) + ai3 * B(3,1);
P(i,2) = ai0 * B(0,2) + ai1 * B(1,2) + ai2 * B(2,2) + ai3 * B(3,2);
P(i,3) = ai0 * B(0,3) + ai1 * B(1,3) + ai2 * B(2,3) + ai3 * B(3,3);
}
#undef A
#undef B
#undef P
}
/*
* Compute inverse of 4x4 transformation matrix.
* Code contributed by Jacques Leroy jle@star.be
* Return GL_TRUE for success, GL_FALSE for failure (singular matrix)
*/
static GLboolean invert_matrix( const GLfloat *m, GLfloat *out )
{
/* NB. OpenGL Matrices are COLUMN major. */
#define SWAP_ROWS(a, b) { GLfloat *_tmp = a; (a)=(b); (b)=_tmp; }
#define MAT(m,r,c) (m)[(c)*4+(r)]
GLfloat wtmp[4][8];
GLfloat m0, m1, m2, m3, s;
GLfloat *r0, *r1, *r2, *r3;
r0 = wtmp[0], r1 = wtmp[1], r2 = wtmp[2], r3 = wtmp[3];
r0[0] = MAT(m,0,0), r0[1] = MAT(m,0,1),
r0[2] = MAT(m,0,2), r0[3] = MAT(m,0,3),
r0[4] = 1.0, r0[5] = r0[6] = r0[7] = 0.0,
r1[0] = MAT(m,1,0), r1[1] = MAT(m,1,1),
r1[2] = MAT(m,1,2), r1[3] = MAT(m,1,3),
r1[5] = 1.0, r1[4] = r1[6] = r1[7] = 0.0,
r2[0] = MAT(m,2,0), r2[1] = MAT(m,2,1),
r2[2] = MAT(m,2,2), r2[3] = MAT(m,2,3),
r2[6] = 1.0, r2[4] = r2[5] = r2[7] = 0.0,
r3[0] = MAT(m,3,0), r3[1] = MAT(m,3,1),
r3[2] = MAT(m,3,2), r3[3] = MAT(m,3,3),
r3[7] = 1.0, r3[4] = r3[5] = r3[6] = 0.0;
/* choose pivot - or die */
if (fabs(r3[0])>fabs(r2[0])) SWAP_ROWS(r3, r2);
if (fabs(r2[0])>fabs(r1[0])) SWAP_ROWS(r2, r1);
if (fabs(r1[0])>fabs(r0[0])) SWAP_ROWS(r1, r0);
if (0.0 == r0[0]) return GL_FALSE;
/* eliminate first variable */
m1 = r1[0]/r0[0]; m2 = r2[0]/r0[0]; m3 = r3[0]/r0[0];
s = r0[1]; r1[1] -= m1 * s; r2[1] -= m2 * s; r3[1] -= m3 * s;
s = r0[2]; r1[2] -= m1 * s; r2[2] -= m2 * s; r3[2] -= m3 * s;
s = r0[3]; r1[3] -= m1 * s; r2[3] -= m2 * s; r3[3] -= m3 * s;
s = r0[4];
if (s != 0.0) { r1[4] -= m1 * s; r2[4] -= m2 * s; r3[4] -= m3 * s; }
s = r0[5];
if (s != 0.0) { r1[5] -= m1 * s; r2[5] -= m2 * s; r3[5] -= m3 * s; }
s = r0[6];
if (s != 0.0) { r1[6] -= m1 * s; r2[6] -= m2 * s; r3[6] -= m3 * s; }
s = r0[7];
if (s != 0.0) { r1[7] -= m1 * s; r2[7] -= m2 * s; r3[7] -= m3 * s; }
/* choose pivot - or die */
if (fabs(r3[1])>fabs(r2[1])) SWAP_ROWS(r3, r2);
if (fabs(r2[1])>fabs(r1[1])) SWAP_ROWS(r2, r1);
if (0.0 == r1[1]) return GL_FALSE;
/* eliminate second variable */
m2 = r2[1]/r1[1]; m3 = r3[1]/r1[1];
r2[2] -= m2 * r1[2]; r3[2] -= m3 * r1[2];
r2[3] -= m2 * r1[3]; r3[3] -= m3 * r1[3];
s = r1[4]; if (0.0 != s) { r2[4] -= m2 * s; r3[4] -= m3 * s; }
s = r1[5]; if (0.0 != s) { r2[5] -= m2 * s; r3[5] -= m3 * s; }
s = r1[6]; if (0.0 != s) { r2[6] -= m2 * s; r3[6] -= m3 * s; }
s = r1[7]; if (0.0 != s) { r2[7] -= m2 * s; r3[7] -= m3 * s; }
/* choose pivot - or die */
if (fabs(r3[2])>fabs(r2[2])) SWAP_ROWS(r3, r2);
if (0.0 == r2[2]) return GL_FALSE;
/* eliminate third variable */
m3 = r3[2]/r2[2];
r3[3] -= m3 * r2[3], r3[4] -= m3 * r2[4],
r3[5] -= m3 * r2[5], r3[6] -= m3 * r2[6],
r3[7] -= m3 * r2[7];
/* last check */
if (0.0 == r3[3]) return GL_FALSE;
s = 1.0/r3[3]; /* now back substitute row 3 */
r3[4] *= s; r3[5] *= s; r3[6] *= s; r3[7] *= s;
m2 = r2[3]; /* now back substitute row 2 */
s = 1.0/r2[2];
r2[4] = s * (r2[4] - r3[4] * m2), r2[5] = s * (r2[5] - r3[5] * m2),
r2[6] = s * (r2[6] - r3[6] * m2), r2[7] = s * (r2[7] - r3[7] * m2);
m1 = r1[3];
r1[4] -= r3[4] * m1, r1[5] -= r3[5] * m1,
r1[6] -= r3[6] * m1, r1[7] -= r3[7] * m1;
m0 = r0[3];
r0[4] -= r3[4] * m0, r0[5] -= r3[5] * m0,
r0[6] -= r3[6] * m0, r0[7] -= r3[7] * m0;
m1 = r1[2]; /* now back substitute row 1 */
s = 1.0/r1[1];
r1[4] = s * (r1[4] - r2[4] * m1), r1[5] = s * (r1[5] - r2[5] * m1),
r1[6] = s * (r1[6] - r2[6] * m1), r1[7] = s * (r1[7] - r2[7] * m1);
m0 = r0[2];
r0[4] -= r2[4] * m0, r0[5] -= r2[5] * m0,
r0[6] -= r2[6] * m0, r0[7] -= r2[7] * m0;
m0 = r0[1]; /* now back substitute row 0 */
s = 1.0/r0[0];
r0[4] = s * (r0[4] - r1[4] * m0), r0[5] = s * (r0[5] - r1[5] * m0),
r0[6] = s * (r0[6] - r1[6] * m0), r0[7] = s * (r0[7] - r1[7] * m0);
MAT(out,0,0) = r0[4]; MAT(out,0,1) = r0[5],
MAT(out,0,2) = r0[6]; MAT(out,0,3) = r0[7],
MAT(out,1,0) = r1[4]; MAT(out,1,1) = r1[5],
MAT(out,1,2) = r1[6]; MAT(out,1,3) = r1[7],
MAT(out,2,0) = r2[4]; MAT(out,2,1) = r2[5],
MAT(out,2,2) = r2[6]; MAT(out,2,3) = r2[7],
MAT(out,3,0) = r3[4]; MAT(out,3,1) = r3[5],
MAT(out,3,2) = r3[6]; MAT(out,3,3) = r3[7];
return GL_TRUE;
#undef MAT
#undef SWAP_ROWS
}
/*
* Determine if the given matrix is the identity matrix.
*/
static GLboolean is_identity( const GLfloat m[16] )
{
if ( m[0]==1.0F && m[4]==0.0F && m[ 8]==0.0F && m[12]==0.0F
&& m[1]==0.0F && m[5]==1.0F && m[ 9]==0.0F && m[13]==0.0F
&& m[2]==0.0F && m[6]==0.0F && m[10]==1.0F && m[14]==0.0F
&& m[3]==0.0F && m[7]==0.0F && m[11]==0.0F && m[15]==1.0F) {
return GL_TRUE;
}
else {
return GL_FALSE;
}
}
/*
* Examine the current modelview matrix to determine its type.
* Later we use the matrix type to optimize vertex transformations.
*/
void gl_analyze_modelview_matrix( GLcontext *ctx )
{
const GLfloat *m = ctx->ModelViewMatrix;
if (is_identity(m)) {
ctx->ModelViewMatrixType = MATRIX_IDENTITY;
}
else if ( m[4]==0.0F && m[ 8]==0.0F
&& m[1]==0.0F && m[ 9]==0.0F
&& m[2]==0.0F && m[6]==0.0F && m[10]==1.0F && m[14]==0.0F
&& m[3]==0.0F && m[7]==0.0F && m[11]==0.0F && m[15]==1.0F) {
ctx->ModelViewMatrixType = MATRIX_2D_NO_ROT;
}
else if ( m[ 8]==0.0F
&& m[ 9]==0.0F
&& m[2]==0.0F && m[6]==0.0F && m[10]==1.0F && m[14]==0.0F
&& m[3]==0.0F && m[7]==0.0F && m[11]==0.0F && m[15]==1.0F) {
ctx->ModelViewMatrixType = MATRIX_2D;
}
else if (m[3]==0.0F && m[7]==0.0F && m[11]==0.0F && m[15]==1.0F) {
ctx->ModelViewMatrixType = MATRIX_3D;
}
else {
ctx->ModelViewMatrixType = MATRIX_GENERAL;
}
if (!invert_matrix( ctx->ModelViewMatrix, ctx->ModelViewInv )) {
MEMCPY( ctx->ModelViewInv, Identity, 16 * sizeof(GLfloat) );
}
ctx->NewModelViewMatrix = GL_FALSE;
}
/*
* Examine the current projection matrix to determine its type.
* Later we use the matrix type to optimize vertex transformations.
*/
void gl_analyze_projection_matrix( GLcontext *ctx )
{
/* look for common-case ortho and perspective matrices */
const GLfloat *m = ctx->ProjectionMatrix;
if (is_identity(m)) {
ctx->ProjectionMatrixType = MATRIX_IDENTITY;
}
else if ( m[4]==0.0F && m[8] ==0.0F
&& m[1]==0.0F && m[9] ==0.0F
&& m[2]==0.0F && m[6]==0.0F
&& m[3]==0.0F && m[7]==0.0F && m[11]==0.0F && m[15]==1.0F) {
ctx->ProjectionMatrixType = MATRIX_ORTHO;
}
else if ( m[4]==0.0F && m[12]==0.0F
&& m[1]==0.0F && m[13]==0.0F
&& m[2]==0.0F && m[6]==0.0F
&& m[3]==0.0F && m[7]==0.0F && m[11]==-1.0F && m[15]==0.0F) {
ctx->ProjectionMatrixType = MATRIX_PERSPECTIVE;
}
else {
ctx->ProjectionMatrixType = MATRIX_GENERAL;
}
ctx->NewProjectionMatrix = GL_FALSE;
}
/*
* Examine the current texture matrix to determine its type.
* Later we use the matrix type to optimize texture coordinate transformations.
*/
void gl_analyze_texture_matrix( GLcontext *ctx )
{
GLuint texSet;
for (texSet = 0; texSet<MAX_TEX_COORD_SETS; texSet++) {
const GLfloat *m = ctx->TextureMatrix[texSet];
if (is_identity(m)) {
ctx->TextureMatrixType[texSet] = MATRIX_IDENTITY;
}
else if ( m[ 8]==0.0F
&& m[ 9]==0.0F
&& m[2]==0.0F && m[6]==0.0F && m[10]==1.0F && m[14]==0.0F
&& m[3]==0.0F && m[7]==0.0F && m[11]==0.0F && m[15]==1.0F) {
ctx->TextureMatrixType[texSet] = MATRIX_2D;
}
else if (m[3]==0.0F && m[7]==0.0F && m[11]==0.0F && m[15]==1.0F) {
ctx->TextureMatrixType[texSet] = MATRIX_3D;
}
else {
ctx->TextureMatrixType[texSet] = MATRIX_GENERAL;
}
}
ctx->NewTextureMatrix = GL_FALSE;
}
void gl_Frustum( GLcontext *ctx,
GLdouble left, GLdouble right,
GLdouble bottom, GLdouble top,
GLdouble nearval, GLdouble farval )
{
GLfloat x, y, a, b, c, d;
GLfloat m[16];
if (nearval<=0.0 || farval<=0.0) {
gl_error( ctx, GL_INVALID_VALUE, "glFrustum(near or far)" );
}
x = (2.0*nearval) / (right-left);
y = (2.0*nearval) / (top-bottom);
a = (right+left) / (right-left);
b = (top+bottom) / (top-bottom);
c = -(farval+nearval) / ( farval-nearval);
d = -(2.0*farval*nearval) / (farval-nearval); /* error? */
#define M(row,col) m[col*4+row]
M(0,0) = x; M(0,1) = 0.0F; M(0,2) = a; M(0,3) = 0.0F;
M(1,0) = 0.0F; M(1,1) = y; M(1,2) = b; M(1,3) = 0.0F;
M(2,0) = 0.0F; M(2,1) = 0.0F; M(2,2) = c; M(2,3) = d;
M(3,0) = 0.0F; M(3,1) = 0.0F; M(3,2) = -1.0F; M(3,3) = 0.0F;
#undef M
gl_MultMatrixf( ctx, m );
/* Need to keep a stack of near/far values in case the user push/pops
* the projection matrix stack so that we can call Driver.NearFar()
* after a pop.
*/
ctx->NearFarStack[ctx->ProjectionStackDepth][0] = nearval;
ctx->NearFarStack[ctx->ProjectionStackDepth][1] = farval;
if (ctx->Driver.NearFar) {
(*ctx->Driver.NearFar)( ctx, nearval, farval );
}
}
void gl_Ortho( GLcontext *ctx,
GLdouble left, GLdouble right,
GLdouble bottom, GLdouble top,
GLdouble nearval, GLdouble farval )
{
GLfloat x, y, z;
GLfloat tx, ty, tz;
GLfloat m[16];
x = 2.0 / (right-left);
y = 2.0 / (top-bottom);
z = -2.0 / (farval-nearval);
tx = -(right+left) / (right-left);
ty = -(top+bottom) / (top-bottom);
tz = -(farval+nearval) / (farval-nearval);
#define M(row,col) m[col*4+row]
M(0,0) = x; M(0,1) = 0.0F; M(0,2) = 0.0F; M(0,3) = tx;
M(1,0) = 0.0F; M(1,1) = y; M(1,2) = 0.0F; M(1,3) = ty;
M(2,0) = 0.0F; M(2,1) = 0.0F; M(2,2) = z; M(2,3) = tz;
M(3,0) = 0.0F; M(3,1) = 0.0F; M(3,2) = 0.0F; M(3,3) = 1.0F;
#undef M
gl_MultMatrixf( ctx, m );
if (ctx->Driver.NearFar) {
(*ctx->Driver.NearFar)( ctx, nearval, farval );
}
}
void gl_MatrixMode( GLcontext *ctx, GLenum mode )
{
if (INSIDE_BEGIN_END(ctx)) {
gl_error( ctx, GL_INVALID_OPERATION, "glMatrixMode" );
return;
}
switch (mode) {
case GL_MODELVIEW:
case GL_PROJECTION:
case GL_TEXTURE:
ctx->Transform.MatrixMode = mode;
break;
default:
gl_error( ctx, GL_INVALID_ENUM, "glMatrixMode" );
}
}
void gl_PushMatrix( GLcontext *ctx )
{
if (INSIDE_BEGIN_END(ctx)) {
gl_error( ctx, GL_INVALID_OPERATION, "glPushMatrix" );
return;
}
switch (ctx->Transform.MatrixMode) {
case GL_MODELVIEW:
if (ctx->ModelViewStackDepth>=MAX_MODELVIEW_STACK_DEPTH-1) {
gl_error( ctx, GL_STACK_OVERFLOW, "glPushMatrix");
return;
}
MEMCPY( ctx->ModelViewStack[ctx->ModelViewStackDepth],
ctx->ModelViewMatrix,
16*sizeof(GLfloat) );
ctx->ModelViewStackDepth++;
break;
case GL_PROJECTION:
if (ctx->ProjectionStackDepth>=MAX_PROJECTION_STACK_DEPTH) {
gl_error( ctx, GL_STACK_OVERFLOW, "glPushMatrix");
return;
}
MEMCPY( ctx->ProjectionStack[ctx->ProjectionStackDepth],
ctx->ProjectionMatrix,
16*sizeof(GLfloat) );
ctx->ProjectionStackDepth++;
/* Save near and far projection values */
ctx->NearFarStack[ctx->ProjectionStackDepth][0]
= ctx->NearFarStack[ctx->ProjectionStackDepth-1][0];
ctx->NearFarStack[ctx->ProjectionStackDepth][1]
= ctx->NearFarStack[ctx->ProjectionStackDepth-1][1];
break;
case GL_TEXTURE:
{
GLuint texSet = ctx->Texture.CurrentTransformSet;
if (ctx->TextureStackDepth[texSet] >= MAX_TEXTURE_STACK_DEPTH) {
gl_error( ctx, GL_STACK_OVERFLOW, "glPushMatrix");
return;
}
MEMCPY( ctx->TextureStack[texSet][ctx->TextureStackDepth[texSet]],
ctx->TextureMatrix[texSet],
16*sizeof(GLfloat) );
ctx->TextureStackDepth[texSet]++;
}
break;
default:
gl_problem(ctx, "Bad matrix mode in gl_PushMatrix");
}
}
void gl_PopMatrix( GLcontext *ctx )
{
if (INSIDE_BEGIN_END(ctx)) {
gl_error( ctx, GL_INVALID_OPERATION, "glPopMatrix" );
return;
}
switch (ctx->Transform.MatrixMode) {
case GL_MODELVIEW:
if (ctx->ModelViewStackDepth==0) {
gl_error( ctx, GL_STACK_UNDERFLOW, "glPopMatrix");
return;
}
ctx->ModelViewStackDepth--;
MEMCPY( ctx->ModelViewMatrix,
ctx->ModelViewStack[ctx->ModelViewStackDepth],
16*sizeof(GLfloat) );
ctx->NewModelViewMatrix = GL_TRUE;
break;
case GL_PROJECTION:
if (ctx->ProjectionStackDepth==0) {
gl_error( ctx, GL_STACK_UNDERFLOW, "glPopMatrix");
return;
}
ctx->ProjectionStackDepth--;
MEMCPY( ctx->ProjectionMatrix,
ctx->ProjectionStack[ctx->ProjectionStackDepth],
16*sizeof(GLfloat) );
ctx->NewProjectionMatrix = GL_TRUE;
/* Device driver near/far values */
{
GLfloat nearVal = ctx->NearFarStack[ctx->ProjectionStackDepth][0];
GLfloat farVal = ctx->NearFarStack[ctx->ProjectionStackDepth][1];
if (ctx->Driver.NearFar) {
(*ctx->Driver.NearFar)( ctx, nearVal, farVal );
}
}
break;
case GL_TEXTURE:
{
GLuint texSet = ctx->Texture.CurrentTransformSet;
if (ctx->TextureStackDepth[texSet]==0) {
gl_error( ctx, GL_STACK_UNDERFLOW, "glPopMatrix");
return;
}
ctx->TextureStackDepth[texSet]--;
MEMCPY( ctx->TextureMatrix[texSet],
ctx->TextureStack[texSet][ctx->TextureStackDepth[texSet]],
16*sizeof(GLfloat) );
ctx->NewTextureMatrix = GL_TRUE;
}
break;
default:
gl_problem(ctx, "Bad matrix mode in gl_PopMatrix");
}
}
void gl_LoadIdentity( GLcontext *ctx )
{
if (INSIDE_BEGIN_END(ctx)) {
gl_error( ctx, GL_INVALID_OPERATION, "glLoadIdentity" );
return;
}
switch (ctx->Transform.MatrixMode) {
case GL_MODELVIEW:
MEMCPY( ctx->ModelViewMatrix, Identity, 16*sizeof(GLfloat) );
MEMCPY( ctx->ModelViewInv, Identity, 16*sizeof(GLfloat) );
ctx->ModelViewMatrixType = MATRIX_IDENTITY;
ctx->NewModelViewMatrix = GL_FALSE;
break;
case GL_PROJECTION:
MEMCPY( ctx->ProjectionMatrix, Identity, 16*sizeof(GLfloat) );
ctx->ProjectionMatrixType = MATRIX_IDENTITY;
ctx->NewProjectionMatrix = GL_FALSE;
break;
case GL_TEXTURE:
{
GLuint texSet = ctx->Texture.CurrentTransformSet;
MEMCPY( ctx->TextureMatrix[texSet], Identity, 16*sizeof(GLfloat) );
ctx->TextureMatrixType[texSet] = MATRIX_IDENTITY;
ctx->NewTextureMatrix = GL_FALSE;
}
break;
default:
gl_problem(ctx, "Bad matrix mode in gl_LoadIdentity");
}
}
void gl_LoadMatrixf( GLcontext *ctx, const GLfloat *m )
{
if (INSIDE_BEGIN_END(ctx)) {
gl_error( ctx, GL_INVALID_OPERATION, "glLoadMatrix" );
return;
}
switch (ctx->Transform.MatrixMode) {
case GL_MODELVIEW:
MEMCPY( ctx->ModelViewMatrix, m, 16*sizeof(GLfloat) );
ctx->NewModelViewMatrix = GL_TRUE;
break;
case GL_PROJECTION:
MEMCPY( ctx->ProjectionMatrix, m, 16*sizeof(GLfloat) );
ctx->NewProjectionMatrix = GL_TRUE;
{
GLfloat n, f, c, d;
#define M(row,col) m[col*4+row]
c = M(2,2);
d = M(2,3);
#undef M
if (c == 1.0)
n = 0.0;
else
n = d / (c - 1.0);
if (c == -1.0)
f = 1.0;
else
f = d / (c + 1.0);
/* Need to keep a stack of near/far values in case the user
* push/pops the projection matrix stack so that we can call
* Driver.NearFar() after a pop.
*/
ctx->NearFarStack[ctx->ProjectionStackDepth][0] = n;
ctx->NearFarStack[ctx->ProjectionStackDepth][1] = f;
if (ctx->Driver.NearFar) {
(*ctx->Driver.NearFar)( ctx, n, f );
}
}
break;
case GL_TEXTURE:
{
GLuint texSet = ctx->Texture.CurrentTransformSet;
MEMCPY( ctx->TextureMatrix[texSet], m, 16*sizeof(GLfloat) );
ctx->NewTextureMatrix = GL_TRUE;
}
break;
default:
gl_problem(ctx, "Bad matrix mode in gl_LoadMatrixf");
}
}
void gl_MultMatrixf( GLcontext *ctx, const GLfloat *m )
{
if (INSIDE_BEGIN_END(ctx)) {
gl_error( ctx, GL_INVALID_OPERATION, "glMultMatrix" );
return;
}
switch (ctx->Transform.MatrixMode) {
case GL_MODELVIEW:
matmul( ctx->ModelViewMatrix, ctx->ModelViewMatrix, m );
ctx->NewModelViewMatrix = GL_TRUE;
break;
case GL_PROJECTION:
matmul( ctx->ProjectionMatrix, ctx->ProjectionMatrix, m );
ctx->NewProjectionMatrix = GL_TRUE;
break;
case GL_TEXTURE:
{
GLuint texSet = ctx->Texture.CurrentTransformSet;
matmul( ctx->TextureMatrix[texSet], ctx->TextureMatrix[texSet], m );
ctx->NewTextureMatrix = GL_TRUE;
}
break;
default:
gl_problem(ctx, "Bad matrix mode in gl_MultMatrixf");
}
}
/*
* Generate a 4x4 transformation matrix from glRotate parameters.
*/
void gl_rotation_matrix( GLfloat angle, GLfloat x, GLfloat y, GLfloat z,
GLfloat m[] )
{
/* This function contributed by Erich Boleyn (erich@uruk.org) */
GLfloat mag, s, c;
GLfloat xx, yy, zz, xy, yz, zx, xs, ys, zs, one_c;
s = sin( angle * DEG2RAD );
c = cos( angle * DEG2RAD );
mag = GL_SQRT( x*x + y*y + z*z );
if (mag == 0.0) {
/* generate an identity matrix and return */
MEMCPY(m, Identity, sizeof(GLfloat)*16);
return;
}
x /= mag;
y /= mag;
z /= mag;
#define M(row,col) m[col*4+row]
/*
* Arbitrary axis rotation matrix.
*
* This is composed of 5 matrices, Rz, Ry, T, Ry', Rz', multiplied
* like so: Rz * Ry * T * Ry' * Rz'. T is the final rotation
* (which is about the X-axis), and the two composite transforms
* Ry' * Rz' and Rz * Ry are (respectively) the rotations necessary
* from the arbitrary axis to the X-axis then back. They are
* all elementary rotations.
*
* Rz' is a rotation about the Z-axis, to bring the axis vector
* into the x-z plane. Then Ry' is applied, rotating about the
* Y-axis to bring the axis vector parallel with the X-axis. The
* rotation about the X-axis is then performed. Ry and Rz are
* simply the respective inverse transforms to bring the arbitrary
* axis back to it's original orientation. The first transforms
* Rz' and Ry' are considered inverses, since the data from the
* arbitrary axis gives you info on how to get to it, not how
* to get away from it, and an inverse must be applied.
*
* The basic calculation used is to recognize that the arbitrary
* axis vector (x, y, z), since it is of unit length, actually
* represents the sines and cosines of the angles to rotate the
* X-axis to the same orientation, with theta being the angle about
* Z and phi the angle about Y (in the order described above)
* as follows:
*
* cos ( theta ) = x / sqrt ( 1 - z^2 )
* sin ( theta ) = y / sqrt ( 1 - z^2 )
*
* cos ( phi ) = sqrt ( 1 - z^2 )
* sin ( phi ) = z
*
* Note that cos ( phi ) can further be inserted to the above
* formulas:
*
* cos ( theta ) = x / cos ( phi )
* sin ( theta ) = y / sin ( phi )
*
* ...etc. Because of those relations and the standard trigonometric
* relations, it is pssible to reduce the transforms down to what
* is used below. It may be that any primary axis chosen will give the
* same results (modulo a sign convention) using thie method.
*
* Particularly nice is to notice that all divisions that might
* have caused trouble when parallel to certain planes or
* axis go away with care paid to reducing the expressions.
* After checking, it does perform correctly under all cases, since
* in all the cases of division where the denominator would have
* been zero, the numerator would have been zero as well, giving
* the expected result.
*/
xx = x * x;
yy = y * y;
zz = z * z;
xy = x * y;
yz = y * z;
zx = z * x;
xs = x * s;
ys = y * s;
zs = z * s;
one_c = 1.0F - c;
M(0,0) = (one_c * xx) + c;
M(0,1) = (one_c * xy) - zs;
M(0,2) = (one_c * zx) + ys;
M(0,3) = 0.0F;
M(1,0) = (one_c * xy) + zs;
M(1,1) = (one_c * yy) + c;
M(1,2) = (one_c * yz) - xs;
M(1,3) = 0.0F;
M(2,0) = (one_c * zx) - ys;
M(2,1) = (one_c * yz) + xs;
M(2,2) = (one_c * zz) + c;
M(2,3) = 0.0F;
M(3,0) = 0.0F;
M(3,1) = 0.0F;
M(3,2) = 0.0F;
M(3,3) = 1.0F;
#undef M
}
void gl_Rotatef( GLcontext *ctx,
GLfloat angle, GLfloat x, GLfloat y, GLfloat z )
{
GLfloat m[16];
gl_rotation_matrix( angle, x, y, z, m );
gl_MultMatrixf( ctx, m );
}
/*
* Execute a glScale call
*/
void gl_Scalef( GLcontext *ctx, GLfloat x, GLfloat y, GLfloat z )
{
GLfloat *m;
if (INSIDE_BEGIN_END(ctx)) {
gl_error( ctx, GL_INVALID_OPERATION, "glScale" );
return;
}
switch (ctx->Transform.MatrixMode) {
case GL_MODELVIEW:
m = ctx->ModelViewMatrix;
ctx->NewModelViewMatrix = GL_TRUE;
break;
case GL_PROJECTION:
m = ctx->ProjectionMatrix;
ctx->NewProjectionMatrix = GL_TRUE;
break;
case GL_TEXTURE:
{
GLuint texSet = ctx->Texture.CurrentTransformSet;
m = ctx->TextureMatrix[texSet];
ctx->NewTextureMatrix = GL_TRUE;
}
break;
default:
gl_problem(ctx, "Bad matrix mode in gl_Scalef");
return;
}
m[0] *= x; m[4] *= y; m[8] *= z;
m[1] *= x; m[5] *= y; m[9] *= z;
m[2] *= x; m[6] *= y; m[10] *= z;
m[3] *= x; m[7] *= y; m[11] *= z;
}
/*
* Execute a glTranslate call
*/
void gl_Translatef( GLcontext *ctx, GLfloat x, GLfloat y, GLfloat z )
{
GLfloat *m;
if (INSIDE_BEGIN_END(ctx)) {
gl_error( ctx, GL_INVALID_OPERATION, "glTranslate" );
return;
}
switch (ctx->Transform.MatrixMode) {
case GL_MODELVIEW:
m = ctx->ModelViewMatrix;
ctx->NewModelViewMatrix = GL_TRUE;
break;
case GL_PROJECTION:
m = ctx->ProjectionMatrix;
ctx->NewProjectionMatrix = GL_TRUE;
break;
case GL_TEXTURE:
{
GLuint texSet = ctx->Texture.CurrentTransformSet;
m = ctx->TextureMatrix[texSet];
ctx->NewTextureMatrix = GL_TRUE;
}
break;
default:
gl_problem(ctx, "Bad matrix mode in gl_Translatef");
return;
}
m[12] = m[0] * x + m[4] * y + m[8] * z + m[12];
m[13] = m[1] * x + m[5] * y + m[9] * z + m[13];
m[14] = m[2] * x + m[6] * y + m[10] * z + m[14];
m[15] = m[3] * x + m[7] * y + m[11] * z + m[15];
}
/*
* Define a new viewport and reallocate auxillary buffers if the size of
* the window (color buffer) has changed.
*/
void gl_Viewport( GLcontext *ctx,
GLint x, GLint y, GLsizei width, GLsizei height )
{
if (width<0 || height<0) {
gl_error( ctx, GL_INVALID_VALUE, "glViewport" );
return;
}
if (INSIDE_BEGIN_END(ctx)) {
gl_error( ctx, GL_INVALID_OPERATION, "glViewport" );
return;
}
/* clamp width, and height to implementation dependent range */
width = CLAMP( width, 1, MAX_WIDTH );
height = CLAMP( height, 1, MAX_HEIGHT );
/* Save viewport */
ctx->Viewport.X = x;
ctx->Viewport.Width = width;
ctx->Viewport.Y = y;
ctx->Viewport.Height = height;
/* compute scale and bias values */
ctx->Viewport.Sx = (GLfloat) width / 2.0F;
ctx->Viewport.Tx = ctx->Viewport.Sx + x;
ctx->Viewport.Sy = (GLfloat) height / 2.0F;
ctx->Viewport.Ty = ctx->Viewport.Sy + y;
ctx->NewState |= NEW_ALL; /* just to be safe */
/* Check if window/buffer has been resized and if so, reallocate the
* ancillary buffers.
*/
gl_ResizeBuffersMESA(ctx);
if (ctx->Driver.Viewport) {
(*ctx->Driver.Viewport)( ctx, x, y, width, height );
}
}
void gl_DepthRange( GLcontext *ctx, GLclampd nearval, GLclampd farval )
{
/*
* nearval - specifies mapping of the near clipping plane to window
* coordinates, default is 0
* farval - specifies mapping of the far clipping plane to window
* coordinates, default is 1
*
* After clipping and div by w, z coords are in -1.0 to 1.0,
* corresponding to near and far clipping planes. glDepthRange
* specifies a linear mapping of the normalized z coords in
* this range to window z coords.
*/
GLfloat n, f;
if (INSIDE_BEGIN_END(ctx)) {
gl_error( ctx, GL_INVALID_OPERATION, "glDepthRange" );
return;
}
n = (GLfloat) CLAMP( nearval, 0.0, 1.0 );
f = (GLfloat) CLAMP( farval, 0.0, 1.0 );
ctx->Viewport.Near = n;
ctx->Viewport.Far = f;
ctx->Viewport.Sz = DEPTH_SCALE * ((f - n) / 2.0);
ctx->Viewport.Tz = DEPTH_SCALE * ((f - n) / 2.0 + n);
if (ctx->Driver.DepthRange) {
(*ctx->Driver.DepthRange)( ctx, nearval, farval );
}
}